package com.hyk.commonLib.common.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by 贺玉琨
 */
public class ReflectUtils {
    public static <T> T getStaticField(String className, String fieldName) {
        try {
            return getStaticField(Class.forName(className), fieldName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T getStaticField(Class<?> clazz, String fieldName) {
        T result = null;
        try {
            Field field;
            if ((field = findField(clazz, fieldName)) == null) {
                return null;
            }
            field.setAccessible(true);
            result = (T) field.get(clazz);
            field.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static <T> T getField(String className, String fieldName) {
        try {
            Class<?> clazz = Class.forName(className);
            return getField(clazz.newInstance(), fieldName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T getField(Object o, String fieldName) {
        if (o == null) return null;
        T result = null;
        try {
            Class<?> clazz = o.getClass();
            Field field;
            if ((field = findField(clazz, fieldName)) == null) {
                return null;
            }
            field.setAccessible(true);
            result = (T) field.get(o);
            field.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void setField(Object o, String fieldName, Object value) {
        if (o == null) return;
        try {
            Class<?> clazz = o.getClass();
            Field field;
            if ((field = findField(clazz, fieldName)) == null) {
                return;
            }
            field.setAccessible(true);
            field.set(o, value);
            field.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static Field findField(Class<?> clazz, String fieldName) {
        Field field = null;
        try {
            field = clazz.getField(fieldName);
        } catch (Exception e) {
            try {
                field = clazz.getDeclaredField(fieldName);
            } catch (Exception e1) {
                if ((clazz = clazz.getSuperclass()) != null) {
                    return findField(clazz, fieldName);
                }
            }
        }
        return field;
    }

    //    ==========================================================================================
    public static <T> T callStaticMethod(String className, String methodName, Object[] params, Class<?>[] paramTypes) {
        T result = null;
        try {
            Class<?> clazz = Class.forName(className);
            Method method;
            if ((method = findMethod(clazz, methodName, paramTypes)) == null) {
                return null;
            }
            method.setAccessible(true);
            result = (T) method.invoke(clazz, params);
            method.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static <T> T callMethod(String className, String methodName) {
        try {
            Class<?> clazz = Class.forName(className);
            return callMethod(clazz.newInstance(), methodName, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T callMethod(String className, String methodName, Object[] params, Class<?>[] paramTypes) {
        try {
            Class<?> clazz = Class.forName(className);
            return callMethod(clazz.newInstance(), methodName, params, paramTypes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T callMethod(Object o, String methodName, Object[] params, Class<?>[] paramTypes) {
        return callMethod(o, o.getClass(), methodName, params, paramTypes);
    }

    public static <T> T callMethod(Object o, Class<?> clazz, String methodName, Object[] params, Class<?>[] paramTypes) {
        if (o == null) return null;
        T result = null;
        try {
            Method method;
            if ((method = findMethod(clazz, methodName, paramTypes)) == null) {
                return null;
            }
            method.setAccessible(true);
            result = (T) method.invoke(o, params);
            method.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private static Method findMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes) {
        Method method = null;
        try {
            method = clazz.getMethod(methodName, paramTypes);
        } catch (Exception e) {
            try {
                method = clazz.getDeclaredMethod(methodName, paramTypes);
            } catch (Exception e1) {
                if ((clazz = clazz.getSuperclass()) != null) {
                    return findMethod(clazz, methodName, paramTypes);
                }
            }
        }
        return method;
    }

}
